VT-d: define a macro for waiting hardare completion
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 5 Jun 2009 08:27:18 +0000 (09:27 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 5 Jun 2009 08:27:18 +0000 (09:27 +0100)
When set some registers of VT-d, it must wait for hardware
completion. There are lots of duplicated code to do that. This patch
defines a macro for it, thus it is much cleaner.

Signed-off-by: Weidong Han <weidong.han@intel.com>
xen/drivers/passthrough/vtd/dmar.h
xen/drivers/passthrough/vtd/intremap.c
xen/drivers/passthrough/vtd/iommu.c
xen/drivers/passthrough/vtd/qinval.c
xen/drivers/passthrough/vtd/utils.c

index 3664b19d2107908bf952f1cde5d3c6c4c7bb04ec..f0bfb541a559ee626d449540c91f073f38d67bf0 100644 (file)
@@ -90,6 +90,20 @@ void dmar_scope_remove_buses(struct dmar_scope *scope, u16 sec, u16 sub);
 
 #define DMAR_OPERATION_TIMEOUT MILLISECS(1000)
 
+#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
+do {                                                \
+    s_time_t start_time = NOW();                    \
+    while (1) {                                     \
+        sts = op(iommu->reg, offset);               \
+        if ( cond )                                 \
+            break;                                  \
+        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )      \
+            panic("%s:%d:%s: DMAR hardware is malfunctional\n", \
+                  __FILE__, __LINE__, __func__);                \
+        cpu_relax();                                            \
+    }                                                           \
+} while (0)
+
 int vtd_hw_check(void);
 void disable_pmr(struct iommu *iommu);
 int is_usb_device(u8 bus, u8 devfn);
index e918708cd1b633919e19d1179f18850984a04aa8..083faa486d3c964014424e21e4b9f56e1d8c3830 100644 (file)
@@ -534,7 +534,7 @@ void msi_msg_write_remap_rte(
 int enable_intremap(struct iommu *iommu)
 {
     struct ir_ctrl *ir_ctrl;
-    s_time_t start_time;
+    u32 sts;
 
     ASSERT(ecap_intr_remap(iommu->ecap) && iommu_intremap);
 
@@ -564,38 +564,22 @@ int enable_intremap(struct iommu *iommu)
     iommu->gcmd |= DMA_GCMD_SIRTP;
     dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
 
-    /* Make sure hardware complete it */
-    start_time = NOW();
-    while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_SIRTPS) )
-    {
-        if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
-            panic("Cannot set SIRTP field for interrupt remapping\n");
-        cpu_relax();
-    }
-
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  (sts & DMA_GSTS_SIRTPS), sts);
     /* enable comaptiblity format interrupt pass through */
     iommu->gcmd |= DMA_GCMD_CFI;
     dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
 
-    start_time = NOW();
-    while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_CFIS) )
-    {
-        if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
-            panic("Cannot set CFI field for interrupt remapping\n");
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  (sts & DMA_GSTS_CFIS), sts);
 
     /* enable interrupt remapping hardware */
     iommu->gcmd |= DMA_GCMD_IRE;
     dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
 
-    start_time = NOW();
-    while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES) )
-    {
-        if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
-            panic("Cannot set IRE field for interrupt remapping\n");
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  (sts & DMA_GSTS_IRES), sts);
 
     /* After set SIRTP, we should do globally invalidate the IEC */
     iommu_flush_iec_global(iommu);
@@ -605,18 +589,13 @@ int enable_intremap(struct iommu *iommu)
 
 void disable_intremap(struct iommu *iommu)
 {
-    s_time_t start_time;
+    u32 sts;
 
     ASSERT(ecap_intr_remap(iommu->ecap) && iommu_intremap);
 
     iommu->gcmd &= ~(DMA_GCMD_SIRTP | DMA_GCMD_CFI | DMA_GCMD_IRE);
     dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
 
-    start_time = NOW();
-    while ( dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES )
-    {
-        if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
-            panic("Cannot clear IRE field for interrupt remapping\n");
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  !(sts & DMA_GSTS_IRES), sts);
 }
index 50e801fe6916650a9bb8bfef076ccfd56c6acb79..96c7ef26be08d6d24a59a9198a301e3e01a31a96 100644 (file)
@@ -230,7 +230,6 @@ static void iommu_flush_write_buffer(struct iommu *iommu)
 {
     u32 val;
     unsigned long flag;
-    s_time_t start_time;
 
     if ( !rwbf_quirk && !cap_rwbf(iommu->cap) )
         return;
@@ -240,17 +239,9 @@ static void iommu_flush_write_buffer(struct iommu *iommu)
     dmar_writel(iommu->reg, DMAR_GCMD_REG, val);
 
     /* Make sure hardware complete it */
-    start_time = NOW();
-    for ( ; ; )
-    {
-        val = dmar_readl(iommu->reg, DMAR_GSTS_REG);
-        if ( !(val & DMA_GSTS_WBFS) )
-            break;
-        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
-            panic("%s: DMAR hardware is malfunctional,"
-                  " please disable IOMMU\n", __func__);
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  !(val & DMA_GSTS_WBFS), val);
+
     spin_unlock_irqrestore(&iommu->register_lock, flag);
 }
 
@@ -263,7 +254,6 @@ static int flush_context_reg(
     struct iommu *iommu = (struct iommu *) _iommu;
     u64 val = 0;
     unsigned long flag;
-    s_time_t start_time;
 
     /*
      * In the non-present entry flush case, if hardware doesn't cache
@@ -301,17 +291,9 @@ static int flush_context_reg(
     dmar_writeq(iommu->reg, DMAR_CCMD_REG, val);
 
     /* Make sure hardware complete it */
-    start_time = NOW();
-    for ( ; ; )
-    {
-        val = dmar_readq(iommu->reg, DMAR_CCMD_REG);
-        if ( !(val & DMA_CCMD_ICC) )
-            break;
-        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
-            panic("%s: DMAR hardware is malfunctional,"
-                  " please disable IOMMU\n", __func__);
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG, dmar_readq,
+                  !(val & DMA_CCMD_ICC), val);
+
     spin_unlock_irqrestore(&iommu->register_lock, flag);
     /* flush context entry will implicitly flush write buffer */
     return 0;
@@ -352,7 +334,6 @@ static int flush_iotlb_reg(void *_iommu, u16 did,
     int tlb_offset = ecap_iotlb_offset(iommu->ecap);
     u64 val = 0, val_iva = 0;
     unsigned long flag;
-    s_time_t start_time;
 
     /*
      * In the non-present entry flush case, if hardware doesn't cache
@@ -399,17 +380,8 @@ static int flush_iotlb_reg(void *_iommu, u16 did,
     dmar_writeq(iommu->reg, tlb_offset + 8, val);
 
     /* Make sure hardware complete it */
-    start_time = NOW();
-    for ( ; ; )
-    {
-        val = dmar_readq(iommu->reg, tlb_offset + 8);
-        if ( !(val & DMA_TLB_IVT) )
-            break;
-        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
-            panic("%s: DMAR hardware is malfunctional,"
-                  " please disable IOMMU\n", __func__);
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, (tlb_offset + 8), dmar_readq,
+                  !(val & DMA_TLB_IVT), val);
     spin_unlock_irqrestore(&iommu->register_lock, flag);
 
     /* check IOTLB invalidation granularity */
@@ -578,7 +550,6 @@ static int iommu_set_root_entry(struct iommu *iommu)
 {
     u32 cmd, sts;
     unsigned long flags;
-    s_time_t start_time;
 
     spin_lock(&iommu->lock);
 
@@ -597,18 +568,8 @@ static int iommu_set_root_entry(struct iommu *iommu)
     dmar_writel(iommu->reg, DMAR_GCMD_REG, cmd);
 
     /* Make sure hardware complete it */
-    start_time = NOW();
-    for ( ; ; )
-    {
-        sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
-        if ( sts & DMA_GSTS_RTPS )
-            break;
-        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
-            panic("%s: DMAR hardware is malfunctional,"
-                  " please disable IOMMU\n", __func__);
-        cpu_relax();
-    }
-
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  (sts & DMA_GSTS_RTPS), sts);
     spin_unlock_irqrestore(&iommu->register_lock, flags);
 
     return 0;
@@ -618,25 +579,16 @@ static void iommu_enable_translation(struct iommu *iommu)
 {
     u32 sts;
     unsigned long flags;
-    s_time_t start_time;
 
     dprintk(XENLOG_INFO VTDPREFIX,
             "iommu_enable_translation: iommu->reg = %p\n", iommu->reg);
     spin_lock_irqsave(&iommu->register_lock, flags);
     iommu->gcmd |= DMA_GCMD_TE;
     dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
+
     /* Make sure hardware complete it */
-    start_time = NOW();
-    for ( ; ; )
-    {
-        sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
-        if ( sts & DMA_GSTS_TES )
-            break;
-        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
-            panic("%s: DMAR hardware is malfunctional,"
-                  " please disable IOMMU\n", __func__);
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  (sts & DMA_GSTS_TES), sts);
 
     /* Disable PMRs when VT-d engine takes effect per spec definition */
     disable_pmr(iommu);
@@ -647,24 +599,14 @@ static void iommu_disable_translation(struct iommu *iommu)
 {
     u32 sts;
     unsigned long flags;
-    s_time_t start_time;
 
     spin_lock_irqsave(&iommu->register_lock, flags);
     iommu->gcmd &= ~ DMA_GCMD_TE;
     dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
 
     /* Make sure hardware complete it */
-    start_time = NOW();
-    for ( ; ; )
-    {
-        sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
-        if ( !(sts & DMA_GSTS_TES) )
-            break;
-        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
-            panic("%s: DMAR hardware is malfunctional,"
-                  " please disable IOMMU\n", __func__);
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  !(sts & DMA_GSTS_TES), sts);
     spin_unlock_irqrestore(&iommu->register_lock, flags);
 }
 
index 5df55dcbd6430f53be6bf74dd1c2c66558270d1e..ebd873eb58a6a4b7fd93d25ae7cd8df02177af9e 100644 (file)
@@ -418,9 +418,9 @@ static int flush_iotlb_qi(
 
 int enable_qinval(struct iommu *iommu)
 {
-    s_time_t start_time;
     struct qi_ctrl *qi_ctrl;
     struct iommu_flush *flush;
+    u32 sts;
 
     qi_ctrl = iommu_qi_ctrl(iommu);
     flush = iommu_get_flush(iommu);
@@ -458,13 +458,8 @@ int enable_qinval(struct iommu *iommu)
     dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
 
     /* Make sure hardware complete it */
-    start_time = NOW();
-    while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_QIES) )
-    {
-        if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
-            panic("Cannot set QIE field for queue invalidation\n");
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  (sts & DMA_GSTS_QIES), sts);
 
     qinval_enabled = 1;
     return 0;
@@ -472,7 +467,7 @@ int enable_qinval(struct iommu *iommu)
 
 void disable_qinval(struct iommu *iommu)
 {
-    s_time_t start_time;
+    u32 sts;
 
     ASSERT(ecap_queued_inval(iommu->ecap) && iommu_qinval);
 
@@ -480,11 +475,6 @@ void disable_qinval(struct iommu *iommu)
     dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
 
     /* Make sure hardware complete it */
-    start_time = NOW();
-    while ( dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_QIES )
-    {
-        if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) )
-            panic("Cannot clear QIE field for queue invalidation\n");
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
+                  !(sts & DMA_GSTS_QIES), sts);
 }
index 9854d146711d7ef45aca94f9ab7cb22ce24daf72..83b6126c57e4f8ec19dd6a288fe330185bf577d2 100644 (file)
@@ -38,27 +38,16 @@ int is_usb_device(u8 bus, u8 devfn)
 /* Disable vt-d protected memory registers. */
 void disable_pmr(struct iommu *iommu)
 {
-    s_time_t start_time;
-    unsigned int val;
+    u32 val;
 
     val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
     if ( !(val & DMA_PMEN_PRS) )
         return;
 
     dmar_writel(iommu->reg, DMAR_PMEN_REG, val & ~DMA_PMEN_EPM);
-    start_time = NOW();
 
-    for ( ; ; )
-    {
-        val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
-        if ( (val & DMA_PMEN_PRS) == 0 )
-            break;
-
-        if ( NOW() > start_time + DMAR_OPERATION_TIMEOUT )
-            panic("Disable PMRs timeout\n");
-
-        cpu_relax();
-    }
+    IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG, dmar_readl,
+                  !(val & DMA_PMEN_PRS), val);
 
     dprintk(XENLOG_INFO VTDPREFIX,
             "Disabled protected memory registers\n");